﻿using Servo_Tool.entity;
using Servo_Tool.utils;
using Servo_Tool.cache;
using Servo_Tool.client;
using Servo_Tool.constant;
using Servo_Tool.domain;
using Servo_Tool.service;
using System;
using System.Collections.Generic;

namespace Servo_Tool.handler
{
    public class WriteHandler
    {
        private readonly string unitNo;
        public event Action<string, string, string> ShowMessageUpdated;
        private readonly IFuncService funcService = new FuncServiceImpl();
        public WriteHandler(string unitNo)
        {
            this.unitNo = unitNo;
        }

        /// <summary>
        /// 点的事件触发成功后调用
        /// </summary>
        /// <param name="itemNo"></param>
        public void WriteByItemNo(string itemNo)
        {
            if (string.IsNullOrEmpty(itemNo))
            {
                return;
            }
            //1.获取点信号相关的事件
            if (GlobalCachePool.item_event_dict.TryGetValue(itemNo, out PlcEventEntity eva))
            {
                string callType = eva.CALL_TYPE;
                string callNo = eva.CALL_NO;
                string param = itemNo;
                string noLogCode = eva.NO_LOG_CODE;

                //1.1.CALL_TYPE=PLC
                if (SymbolConstants.CALL_TYPE_PLC.Equals(callType))
                {
                    if (!GlobalCachePool.write_event_dict.TryGetValue(itemNo, out List<Equation_EVENT> writes))
                    {
                        return;
                    }
                    if (writes == null || writes.Count == 0)
                    {
                        return;
                    }
                    foreach (Equation_EVENT equation in writes)
                    {
                        WriteByEquation(equation);
                    }
                }
                //1.2.CALL_TYPE=PROC
                if (SymbolConstants.CALL_TYPE_PROC.Equals(callType))
                {
                    //调用存储过程
                    ResultData_FUNC resultData_FUNC = funcService.ExecFunction(callNo, param);
                    //输出触发结果
                    string code = resultData_FUNC.Code;
                    string msg = resultData_FUNC.Msg;
                    string writes = resultData_FUNC.Writes;
                    //如果writes有值则写入PLC
                    if (!string.IsNullOrEmpty(writes))
                    {
                        List<Equation_EVENT> equations = EquationUtils.Write2Equations(writes);
                        foreach (Equation_EVENT equation in equations)
                        {
                            WriteByEquation(equation);
                        }
                    }
                    if (!code.Equals(noLogCode))
                    {
                        ShowMessage(code, msg);
                    }
                }
            }
        }

        /// <summary>
        /// 按WRITE内容写入PLC
        /// </summary>
        /// <param name="equation"></param>
        public void WriteByEquation(Equation_EVENT equation)
        {
            string prefix = equation.LEFT_PREFIX;
            string itemNo = equation.LEFT_MARK;
            string value = equation.RIGHT_MARK;
            //根据标签为PLC还是MEM,判断是否往判断往PLC还是往MEM写数据
            if (SymbolConstants.FLAG_PLC.Equals(prefix))
            {
                if (GlobalCachePool.single_plcItem_dict.TryGetValue(itemNo, out PlcItemEntity item))
                {
                    int dbBlock = item.DB_BLOCK;
                    int itemAdr = item.ITEM_ADR;
                    int len = item.DATA_LEN;
                    string typ = item.DISPLAY_TYPE;

                    Write2Plc(dbBlock, itemAdr, item.OFFSET, typ, value);
                }
            }
        }

        /// <summary>
        /// 将数据写入PLC
        /// </summary>
        /// <param name="block">块号或从机ID</param>
        /// <param name="start">开始地址</param>
        /// <param name="data">字节数组</param>
        public void Write2Plc(int dbNumber, int startAdr, int offset, string varTyp, object data)
        {
            //找对应PLC int dbNumber, int startAdr, int offset, string varTyp, object data
            if (GlobalCachePool.s7_clinet.TryGetValue(unitNo, out S7NetClient client))
            {
                client.WriteData(dbNumber, startAdr, offset, varTyp, data);
            }
        }

        public void ShowMessage(string code, string msg)
        {
            ShowMessageUpdated?.Invoke(unitNo, code, msg);
        }
    }
}
